1 module hip.api.graphics.g2d.animation; 2 public import hip.api.renderer.texture; 3 public import hip.api.graphics.color; 4 public import hip.api.data.textureatlas; 5 6 /** 7 * The frame user is responsible for using the frame properties, while the track is responsible 8 * for returning the correct frame 9 */ 10 struct HipAnimationFrame 11 { 12 IHipTextureRegion region; 13 HipColor color = HipColor.white; 14 ///X, Y 15 float[2] offset = [0,0]; 16 17 version(Have_util) 18 { 19 public import hip.util.data_structures:Array2D, Array2D_GC; 20 static HipAnimationFrame[] fromTextureRegions(Array2D!IHipTextureRegion reg, uint startY, uint startX, uint endY, uint endX) 21 { 22 HipAnimationFrame[] ret; 23 24 for(int i = startY; i <= endY; i++) 25 for(int j = startX; j <= endX; j++) 26 ret~= HipAnimationFrame(reg[i,j]); 27 return ret; 28 } 29 static HipAnimationFrame[] fromTextureRegions(Array2D_GC!IHipTextureRegion reg, uint startY, uint startX, uint endY, uint endX) 30 { 31 HipAnimationFrame[] ret; 32 33 for(int i = startY; i <= endY; i++) 34 for(int j = startX; j <= endX; j++) 35 ret~= HipAnimationFrame(reg[i,j]); 36 return ret; 37 } 38 } 39 } 40 41 enum HipAnimationLoopingMode 42 { 43 none, 44 reset, 45 pingpong 46 } 47 48 49 interface IHipAnimationTrack 50 { 51 string name() const; 52 HipAnimationLoopingMode loopingMode() const; 53 HipAnimationLoopingMode loopingMode(HipAnimationLoopingMode mode = HipAnimationLoopingMode.reset); 54 55 bool reverse() const; 56 bool reverse(bool setReverse); 57 ///Returns how many seconds the animation lasts 58 float getDuration() const; 59 60 IHipAnimationTrack addFrames(HipAnimationFrame[] frame...); 61 IHipAnimationTrack addFrames(IHipTextureRegion[] regions...); 62 version(Have_util) 63 { 64 import hip.util.data_structures:Array2D_GC; 65 final IHipAnimationTrack addFrames(Array2D_GC!IHipTextureRegion sheet) 66 { 67 scope IHipTextureRegion[] regions; 68 for(int y = 0; y < sheet.getHeight; y++) 69 for(int x = 0; x < sheet.getWidth; x++) 70 regions~= sheet[y,x]; 71 return addFrames(regions); 72 } 73 } 74 void reset(); 75 void setFrame(uint frame); 76 void setFramesPerSecond(uint framesPerSecond); 77 HipAnimationFrame* getFrameForTime(float time); 78 HipAnimationFrame* getFrameForProgress(float progress); 79 HipAnimationFrame* update(float deltaTime); 80 } 81 82 83 version(ScriptAPI) version = DefineCreateFromAtlas; 84 85 interface IHipAnimation 86 { 87 IHipAnimationTrack getCurrentTrack(); 88 HipAnimationFrame* getCurrentFrame(); 89 final IHipTextureRegion getCurrentRegion() 90 { 91 HipAnimationFrame* frame = getCurrentFrame(); 92 if(frame == null) 93 return null; 94 return frame.region; 95 } 96 97 version(Have_util) version(DefineCreateFromAtlas) 98 { 99 /** 100 * Creates an IHipAnimation from a loaded texture atlas. 101 * Its frames will be checked such as `mySprite${frameNumber}`. 102 * The animation will be named as the string without the number. 103 */ 104 static IHipAnimation createFromAtlas(IHipTextureAtlas atlas, string animationName, uint framesPerSecond = 24) 105 { 106 import hip.util.string:getNumericEnding, lastIndexOf; 107 import hip.util.algorithm; 108 import hip.api.graphics.g2d.renderer2d; 109 import std.algorithm:sort; 110 111 IHipAnimation anim = newHipAnimation(animationName); 112 foreach(string frameName; sort(atlas.frames.keys)) 113 { 114 AtlasFrame* frame = frameName in atlas; 115 string name = frameName; 116 int index = frameName.lastIndexOf(frameName.getNumericEnding); 117 if(index != -1) 118 name = frameName[0..index]; 119 IHipAnimationTrack track = anim.getTrack(name); 120 if(track is null) 121 { 122 anim.addTrack(track = newHipAnimationTrack(name, framesPerSecond, HipAnimationLoopingMode.reset)); 123 } 124 track.addFrames(HipAnimationFrame(frame.region, HipColor.white, [0,0])); 125 126 } 127 return anim; 128 } 129 } 130 131 132 final string getCurrentTrackName() {return getCurrentTrack().name;} 133 IHipAnimation addTrack(IHipAnimationTrack track); 134 void update(float deltaTime); 135 void setTimeScale(float scale); 136 void play(string trackName); 137 IHipAnimationTrack getTrack(string trackName); 138 139 }